<template>
  <div ref="statsRef"></div>
  <div ref="containerRef" class="container"></div>
</template>
<script setup lang="ts">
import {
  AxesHelper,
  BoxGeometry,
  Color,
  Mesh,
  MeshLambertMaterial,
  PerspectiveCamera,
  PlaneGeometry,
  Scene,
  SphereGeometry,
  SpotLight,
  WebGLRenderer,
} from "three";
import { onMounted, ref } from "vue";
import Stats from "stats.js";
const containerRef = ref<HTMLDivElement>();
// 性能监控
const statsRef = ref<HTMLDivElement>();
const stats = new Stats();
stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
// 创建场景
const scene = new Scene();
// 创建透视相机
// 参数：视野角度，宽高比，近平面，远平面
const camera = new PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);
// 相机位置 参数：x,y,z
camera.position.set(-30, 40, 30);
// 相机朝向
camera.lookAt(scene.position);

// 创建渲染器
const renderer = new WebGLRenderer();
// 设置渲染器背景颜色
renderer.setClearColor(new Color(0xeeeeee));
// 渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// ③允许在场景中使用阴影贴图
renderer.shadowMap.enabled = true;

// 创建坐标轴
const axes = new AxesHelper(80);
// 添加坐标轴到场景
scene.add(axes);

// 创建聚光灯 光照强度1.0
const spotLight = new SpotLight(0xffffff, 1.0);
// ①设置聚光灯投射阴影
spotLight.castShadow = true;
//设置光源不随距离衰减
spotLight.decay = 0.0;
// 设置聚光灯位置
spotLight.position.set(-30, 60, -10);
// 添加灯光到场景
scene.add(spotLight);

// 创建矩形平面几何体
const planeGeometry = new PlaneGeometry(60, 20);
// 创建网格非光泽表面的材质 可以投射阴影
const material = new MeshLambertMaterial({ color: 0xccccff });
// 创建网格模型
const meshPlane = new Mesh(planeGeometry, material);
// 设置模型位置
meshPlane.position.set(20, 0, 0);
// 设置模型旋转角度
meshPlane.rotation.x = -0.5 * Math.PI;
// ②材质是否接收阴影
meshPlane.receiveShadow = true;
// 添加网格模型到场景
scene.add(meshPlane);

// 创建立方体几何体
const boxGeometry = new BoxGeometry(4, 4, 4);
// 创建网格非光泽表面的材质 可以投射阴影
const boxMaterial = new MeshLambertMaterial({
  color: 0xff0000,
  wireframe: false, // 开启线框模式
});
// 创建网格模型
const boxMesh = new Mesh(boxGeometry, boxMaterial);
// 设置模型位置
boxMesh.position.set(2, 2, 2);
boxMesh.castShadow = true; // ①设置模型投射阴影
// 添加网格模型到场景
scene.add(boxMesh);

// 创建球体几何体
const sphereGeometry = new SphereGeometry(4);
// 创建网格非光泽表面的材质 可以投射阴影
const sceneMaterial = new MeshLambertMaterial({
  color: 0x7777ff,
  wireframe: false, // 开启线框模式
});
// 创建网格模型
const sphereMesh = new Mesh(sphereGeometry, sceneMaterial);
// 设置模型位置
sphereMesh.position.set(20, 4, 2);
sphereMesh.castShadow = true; // ①设置模型投射阴影
// 添加网格模型到场景
scene.add(sphereMesh);

let step = 0;
/**
 * 动画函数，用于更新场景中的物体状态并渲染场景
 */
function animate() {
  /**
   * 更新统计信息
   */
  stats.update();

  /**
   * 更新立方体网格的旋转
   */
  boxMesh.rotation.x += 0.02;
  boxMesh.rotation.y += 0.03;
  boxMesh.rotation.z += 0.04;

  // 注释掉的代码：更新立方体网格的缩放，使用正弦函数进行变化
  // boxMesh.scale.x = 1 + Math.sin(step);

  /**
   * 更新步长
   */
  step += 0.04;

  /**
   * 更新球体网格的位置
   * 使用正弦和绝对值函数进行x和y坐标的变化
   */
  sphereMesh.position.x = 20 + 10 * Math.cos(step);
  sphereMesh.position.y = 2 + 10 * Math.abs(Math.sin(step));

  /**
   * 递归调用animate函数，使用requestAnimationFrame进行动画循环
   */
  requestAnimationFrame(animate);

  /**
   * 渲染场景
   * 将scene（场景）和camera（相机）传递给renderer（渲染器）进行渲染
   */
  renderer.render(scene, camera);
}
// 初始化动画
animate();
onMounted(() => {
  // 挂载性能监控
  stats.dom.style.top = "50px";
  statsRef.value?.appendChild(stats.dom);
  // DOM挂载后添加渲染渲染器（ref 可能为空）
  containerRef.value?.appendChild(renderer.domElement);
});
</script>
<style lang="scss" scoped></style>
